package com.originskyseed.platform.log.aop;

import java.lang.reflect.Method;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.originskyseed.platform.common.annotation.SysLog;
import com.originskyseed.platform.core.base.BaseResponseBody;
import com.originskyseed.platform.core.common.code.CommonResponseCode;
import com.originskyseed.platform.core.common.util.RequestHandleUtil;
import com.originskyseed.platform.core.filter.helper.SingleSignOnTokenHelper;
import com.originskyseed.platform.core.tenant.util.TenantCodeUtil;
import com.originskyseed.platform.core.util.bean.AccessObjectUtil;
import com.originskyseed.platform.log.model.LoginLog;
import com.originskyseed.platform.log.model.OperLog;
import com.originskyseed.platform.log.service.ILoginLogService;
import com.originskyseed.platform.log.service.ISysLogService;
import com.originskyseed.platform.user.model.UserInfo;
import com.originskyseed.platform.user.service.IUserInfoService;

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;

/**
 * @Description 日志操作AOP
 * @Version V1.0
 **/
@Aspect
@Component
public class SysLogAop {
	private static final Logger logger = LoggerFactory.getLogger(SysLogAop.class);

	@DubboReference
	private ISysLogService sysLogService;

	@DubboReference
	private IUserInfoService userInfoService;

	@DubboReference
	private ILoginLogService loginLogService;

	/**
	 * 1，表示在哪个类的哪个方法进行切入。配置有切入点表达式。 2，对有@SysLog标记的方法,记录其执行参数及返回结果。
	 */
	@Pointcut("@annotation(com.originskyseed.platform.common.annotation.SysLog)")
	public void controllerAspect() {
	}

	/**
	 * 配置controller环绕通知,使用在方法aspect()上注册的切入点
	 */
	@Around("controllerAspect()")
	public Object aroundMethod(ProceedingJoinPoint point) throws Throwable {
		if (logger.isDebugEnabled()) {
			logger.info(">>>>>>>>>>>>>>>进入日志切面<<<<<<<<<<<<<<<<");
		}
		// 获取request请求
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		MethodSignature signature = (MethodSignature) point.getSignature();
		Method method = signature.getMethod();
		Object result = null;
		// 登录日志记录到另外一个地方
		if (method.getName().equals("verification")) {
			String account = request.getParameter("account");
			UserInfo userInfo = this.userInfoService.selectByAccount(account);
			if (userInfo != null) {
				LoginLog loginLog = new LoginLog();
				String ip = AccessObjectUtil.getClientAddress();
				loginLog.setIp(ip);
				loginLog.setAddress(getAddress(ip));
				loginLog.setAccount(userInfo.getAccount());
				loginLog.setUserName(userInfo.getName());
				loginLog.setSourceSys(userInfo.getSourceSys());
				loginLog.setCreateTime(new Date());
				this.loginLogService.saveLog(loginLog);
			}
			result = point.proceed();
		} else {
			// 获取日志注解
			SysLog log = method.getAnnotation(SysLog.class);
			String desc = log.operationDesc();
			String module = log.module();
			// 设置mongodb数据
			String className = point.getTarget().getClass().getName();
			String methodTarget = className.substring(className.lastIndexOf(".") + 1) + "." + point.getSignature().getName() + "()";
			// 记录日志操作
			OperLog operLog = new OperLog();
			operLog.setMethod(methodTarget);
			operLog.setIp(AccessObjectUtil.getClientAddress());// 访问的IP
			operLog.setBrownerNo(getBrownerNo(request));// 浏览器版本
			operLog.setOsNo(getOsNo(request));// 操作系统版本
			operLog.setModule(module);
			operLog.setSource(1);
			operLog.setOperationDesc("模块:" + module + ",操作行为:" + desc);
			// 获取用户
			UserInfo user = SingleSignOnTokenHelper.getCurrentUserInfo(UserInfo.class);
			// 获取请求信息
			String requestData = RequestHandleUtil.getRequestData(request);
			operLog.setParams(requestData);
			if (ObjectUtils.allNotNull(user)) {
				String name = user.getName();
				operLog.setUserName(name);
				operLog.setUserId(user.getId());
				operLog.setUserAccount(user.getAccount());
			} else {
				operLog.setUserName("未登录用户");
			}
			try {
				result = point.proceed();
				// 操作成功
				operLog.setStatus("1");
				if (result instanceof BaseResponseBody) {
					BaseResponseBody baseResponseBody = (BaseResponseBody) result;
					if (baseResponseBody.getCode() != CommonResponseCode.SUCCESS.getCode() && baseResponseBody.getCode() != CommonResponseCode.SUCCESS_AUTHENTICATION.getCode()) {
						operLog.setStatus("0");
						operLog.setMsg(baseResponseBody.getMsg());
					}
				}
			} catch (Throwable e) {
				// 操作失败
				operLog.setStatus("0");
				throw new RuntimeException(e);
			} finally {
				if (operLog.getIsAdd() != null && operLog.getIsAdd() == 0) {
					return result;
				}
				// 保存日志信息到mongodb
				Boolean flag = sysLogService.saveLog(operLog, TenantCodeUtil.getInstance().getServerTenantCode());
				if (flag) {
					logger.info("保存操作日志成功");
				} else {
					logger.info("保存操作日志失败");
				}
			}
		}

		return result;
	}

	/**
	 * 功能：获取浏览器版本
	 * 
	 * @return
	 */
	public static String getBrownerNo(HttpServletRequest request) {
		String userAgent = request.getHeader("user-agent");
		String brownerNo = "";
		String[] brownerNos = { "MSIE", "FIREFOX", "CHROME", "SAFARI", "OPERA" };
		if (userAgent != null) {
			String str = userAgent.toUpperCase();
			for (int i = 0; i < brownerNos.length; i++) {
				if (str.indexOf(brownerNos[i]) > 0) {
					String str1 = str.substring(str.indexOf(brownerNos[i]));
					if (str1.indexOf(";") > 0) {
						brownerNo = str1.substring(0, str1.indexOf(";"));
					} else {
						brownerNo = brownerNos[i];
					}
					break;
				}
			}
		}
		return brownerNo;
	}

	/**
	 * 功能：获取操作系统版本
	 * 
	 * @return
	 */
	public static String getOsNo(HttpServletRequest request) {
		String userAgent = request.getHeader("user-agent");
		String osNo = "";
		String[] osNos = { "WINDOWS NT", "IOS" };
		if (userAgent != null) {
			String str = userAgent.toUpperCase();
			for (int i = 0; i < osNos.length; i++) {
				if (str.indexOf(osNos[i]) > 0) {
					String str1 = str.substring(str.indexOf(osNos[i]));
					if (str1.indexOf(";") > 0) {
						osNo = str1.substring(0, str1.indexOf(";"));
					} else {
						osNo = osNos[i];
					}
					break;
				}
			}
		}
		return osNo;
	}

	/**
	 * 根据ip获取地址
	 * 
	 * @param ip
	 * @return
	 */
	public static String getAddress(String ip) {
		String url = "http://ip.ws.126.net/ipquery?ip=" + ip;
		String str = HttpUtil.get(url);
		if (StringUtils.isNotBlank(str)) {
			String substring = str.substring(str.indexOf("{"), str.indexOf("}") + 1);
			System.out.println(substring);
			cn.hutool.json.JSONObject jsonObject = JSONUtil.parseObj(substring);
			String province = jsonObject.getStr("province");
			String city = jsonObject.getStr("city");
			return province + " " + city;
		}
		return null;
	}

}